package com.wujian.love.controller;

import com.google.common.util.concurrent.RateLimiter;
import com.wujian.love.domin.SeckillMessage;
import com.wujian.love.domin.SeckillOrder;
import com.wujian.love.domin.User;
import com.wujian.love.dto.GoodsVo;
import com.wujian.love.enums.CodeMegEnum;
import com.wujian.love.redis.GoodsKey;
import com.wujian.love.redis.RedisService;
import com.wujian.love.result.JSONResult;
import com.wujian.love.service.IGoodsService;
import com.wujian.love.service.IOrderParentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: SeckillController
 * @Description: 秒杀
 * @Author: wuj
 * @Date: 2020-09-18 10:16
 **/
public class SeckillController {

    @Autowired
    private RedisService redisService;

    @Autowired
    private IOrderParentService iOrderParentService;

    @Autowired
    private IGoodsService goodsService;



    //基于令牌桶算法的限流实现类
    RateLimiter rateLimiter = RateLimiter.create(10);

    //做标记，判断该商品是否被处理过了
    private HashMap<Integer, Boolean> localOverMap = new HashMap<Integer, Boolean>();

    /**
     * GET POST
     * 1、GET幂等,服务端获取数据，无论调用多少次结果都一样
     * 2、POST，向服务端提交数据，不是幂等
     * <p>
     * 将同步下单改为异步下单
     *
     * @param model
     * @param user
     * @param goodsId
     * @return
     */
    @RequestMapping(value = "/do_seckill", method = RequestMethod.POST)
    @ResponseBody
    public JSONResult list(Model model, User user, @RequestParam("goodsId") Integer goodsId) {
        //获取令牌
        // 从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话，
        // 或者如果无法在timeout 过期之前获取得到许可的话，那么立即返回false（无需等待）
        if (!rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
            return JSONResult.errorMsg(CodeMegEnum.getMsgByCode(CodeMegEnum.ACCESS_LIMIT_REACHED.getCode()));
        }

        if (user == null) {
            return JSONResult.errorMsg(CodeMegEnum.getMsgByCode(CodeMegEnum.SERVER_ERROR.getCode()));
        }
        model.addAttribute("user", user);
        //内存标记，减少redis访问
        boolean over = localOverMap.get(goodsId);
        if (over) {
            return JSONResult.errorMsg(CodeMegEnum.getMsgByCode(CodeMegEnum.SECKILL_OVER.getCode()));
        }
        //预减库存
        //10
        long stock = redisService.decr(GoodsKey.getGoodsStock, "" + goodsId);
        if (stock < 0) {
            afterPropertiesSet();
            //10
            long stock2 = redisService.decr(GoodsKey.getGoodsStock, "" + goodsId);
            if (stock2 < 0) {
                localOverMap.put(goodsId, true);
                return JSONResult.errorMsg(CodeMegEnum.getMsgByCode(CodeMegEnum.SECKILL_OVER.getCode()));
            }
        }
        //判断重复秒杀
        SeckillOrder order = iOrderParentService.getOrderByUserIdGoodsId(user.getId(), goodsId);
        if (order != null) {
            return JSONResult.errorMsg(CodeMegEnum.getMsgByCode(CodeMegEnum.REPEATE_SECKILL.getCode()));
        }
        //入队
        SeckillMessage message = new SeckillMessage();
        message.setUser(user);
        message.setGoodsId(goodsId);
        //sender.sendSeckillMessage(message);
        //排队中
        return JSONResult.ok(0);
    }

    /**
     * 系统初始化,将商品信息加载到redis和本地内存
     */
    public void afterPropertiesSet() {
        List<GoodsVo> goodsVoList = goodsService.listGoodsVo();
        if (goodsVoList == null) {
            return;
        }
        for (GoodsVo goods : goodsVoList) {
            redisService.set(GoodsKey.getGoodsStock, "" + goods.getId(), goods.getStockCount());
            //初始化商品都是没有处理过的
            localOverMap.put(goods.getId(), false);
        }
    }

}
